package com.nnnu.wsnackshop.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.nnnu.wsnackshop.pojo.entity.Riders;
import com.nnnu.wsnackshop.pojo.entity.Users;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt工具类
 */
@Slf4j
public class JwtUtil {
    private static final long EXPIRATION = 7200_0000; // 2小时
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 静态初始化块，配置ObjectMapper
    static {
        // 注册JavaTimeModule，处理Java 8日期时间类型
        objectMapper.registerModule(new JavaTimeModule());
        // 禁用将日期写为时间戳的功能
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }

    // 使用更长的固定字符串生成 SecretKey，确保长度至少为 256 位
    private static final String SECRET_STRING = "myFixedSecretKey1234567890myFixedSecretKey1234567890";
    private static final SecretKey SECRET = Keys.hmacShaKeyFor(SECRET_STRING.getBytes(StandardCharsets.UTF_8));

    /**
     * 获取JWT签名密钥
     * 
     * @return SecretKey 密钥
     */
    public static SecretKey getSecretKey() {
        return SECRET;
    }

    /**
     * 创建JWT令牌，仅包含用户名
     * 
     * @param username 用户名
     * @return JWT令牌
     */
    public static String createToken(String username) {
        Date now = new Date();
        Date exp = new Date(now.getTime() + EXPIRATION);
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(SECRET, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 创建包含用户信息的JWT令牌
     * 
     * @param user 用户对象
     * @return JWT令牌
     */
    public static String createTokenWithUser(@NonNull Users user) {
        Date now = new Date();
        Date exp = new Date(now.getTime() + EXPIRATION);

        Map<String, Object> claims = new HashMap<>();
        // 清理敏感字段
        user.setPassword(null);

        // 把用户名加入claims中，确保subject不会被覆盖
        claims.put("sub", user.getUsername());
        claims.put("userType", "user");

        try {
            // 将用户对象序列化为JSON
            String userJson = objectMapper.writeValueAsString(user);
            claims.put("user", userJson);
        } catch (JsonProcessingException e) {
            log.error("用户对象序列化失败", e);
            throw new RuntimeException("用户对象序列化失败", e);
        }

        return Jwts.builder()
                .setClaims(claims) // 先设置claims，包含了subject
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(SECRET, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 创建包含骑手信息的JWT令牌
     * 
     * @param rider 骑手对象
     * @return JWT令牌
     */
    public static String createTokenWithRider(@NonNull Riders rider) {
        Date now = new Date();
        Date exp = new Date(now.getTime() + EXPIRATION);

        Map<String, Object> claims = new HashMap<>();
        // 清理敏感字段
        rider.setPassword(null);

        // 把骑手手机号作为subject
        claims.put("sub", rider.getPhone());
        claims.put("userType", "rider");
        claims.put("riderId", rider.getId());

        try {
            // 将骑手对象序列化为JSON
            String riderJson = objectMapper.writeValueAsString(rider);
            claims.put("rider", riderJson);
        } catch (JsonProcessingException e) {
            log.error("骑手对象序列化失败", e);
            throw new RuntimeException("骑手对象序列化失败", e);
        }

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(SECRET, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 从JWT令牌中获取用户名
     * 
     * @param token JWT令牌
     * @return 用户名
     */
    public static String getUsername(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            // 优先从标准的subject字段获取用户名
            String username = claims.getSubject();

            // 如果subject为null，可能是使用了新格式的token，尝试从claims中获取
            if (username == null && claims.containsKey("sub")) {
                username = claims.get("sub", String.class);
            }

            // 如果还是null，尝试从user对象中获取
            if (username == null && claims.containsKey("user")) {
                String userJson = claims.get("user", String.class);
                if (userJson != null) {
                    try {
                        Users user = objectMapper.readValue(userJson, Users.class);
                        if (user != null) {
                            username = user.getUsername();
                        }
                    } catch (Exception e) {
                        log.error("从user JSON解析用户名失败", e);
                    }
                }
            }

            return username;
        } catch (Exception e) {
            log.error("从token获取用户名失败", e);
            return null;
        }
    }

    /**
     * 从JWT令牌中获取用户对象
     * 
     * @param token JWT令牌
     * @return 用户对象，如果解析失败则返回null
     */
    public static Users getUserFromToken(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            String userJson = claims.get("user", String.class);
            if (userJson != null) {
                return objectMapper.readValue(userJson, Users.class);
            }
        } catch (Exception e) {
            log.error("从JWT令牌解析用户信息失败", e);
        }
        return null;
    }

    /**
     * 从JWT令牌中获取骑手对象
     * 
     * @param token JWT令牌
     * @return 骑手对象，如果解析失败则返回null
     */
    public static Riders getRiderFromToken(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            String riderJson = claims.get("rider", String.class);
            if (riderJson != null) {
                return objectMapper.readValue(riderJson, Riders.class);
            }
        } catch (Exception e) {
            log.error("从JWT令牌解析骑手信息失败", e);
        }
        return null;
    }

    /**
     * 从JWT令牌中获取骑手ID
     * 
     * @param token JWT令牌
     * @return 骑手ID，如果解析失败则返回null
     */
    public static Integer getRiderIdFromToken(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            if (claims.containsKey("riderId")) {
                return claims.get("riderId", Integer.class);
            }

            // 如果直接获取失败，尝试从rider对象中获取
            String riderJson = claims.get("rider", String.class);
            if (riderJson != null) {
                Riders rider = objectMapper.readValue(riderJson, Riders.class);
                if (rider != null) {
                    return rider.getId();
                }
            }
        } catch (Exception e) {
            log.error("从JWT令牌解析骑手ID失败", e);
        }
        return null;
    }

    /**
     * 获取令牌中的用户类型
     * 
     * @param token JWT令牌
     * @return 用户类型：user或rider
     */
    public static String getUserTypeFromToken(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            if (claims.containsKey("userType")) {
                return claims.get("userType", String.class);
            }
        } catch (Exception e) {
            log.error("从JWT令牌解析用户类型失败", e);
        }
        return "user"; // 默认返回普通用户类型
    }

    /**
     * 验证JWT令牌是否有效
     * 
     * @param token    JWT令牌
     * @param username 用户名
     * @return true表示有效，false表示无效
     */
    public static boolean verify(String token, @NonNull String username) {
        try {
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(SECRET)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            // 检查过期时间
            if (!claims.getExpiration().after(new Date())) {
                return false; // Token已过期
            }

            // 获取用户名（可能来自不同位置，与getUsername方法逻辑保持一致）
            String tokenUsername = claims.getSubject();

            // 如果subject为null，尝试从claims中获取
            if (tokenUsername == null && claims.containsKey("sub")) {
                tokenUsername = claims.get("sub", String.class);
            }

            // 如果tokenUsername为null，尝试从user对象中获取
            if (tokenUsername == null && claims.containsKey("user")) {
                String userJson = claims.get("user", String.class);
                if (userJson != null) {
                    try {
                        Users user = objectMapper.readValue(userJson, Users.class);
                        if (user != null) {
                            tokenUsername = user.getUsername();
                        }
                    } catch (Exception e) {
                        log.error("从user JSON解析用户名失败", e);
                        return false;
                    }
                }
            }

            // 验证用户名是否匹配
            return username.equals(tokenUsername);
        } catch (JwtException e) {
            log.error("JWT验证失败", e);
            return false;
        }
    }
}